from itertools import chain
import ast
import json
import re

class Convertor:
    def __init__(self, ident, style):
        match style:
            case 'snake' | 'upper_snake':
                self.elems = ident.split('_')
            case 'camel':
                self.elems = chain((re.match(r'^[a-z]*', ident).group(), ), re.findall(r'[A-Z][a-z]*', ident))
            case 'pascal':
                self.elems = re.findall(r'[A-Z][a-z]*', ident)
            case 'kebab':
                self.elems = ident.split('-')
            case 'url':
                self.elems = ident.split('/')
            case 'text':
                self.elems = ident.split()
        self.elems = map(str.lower, self.elems)

    def export(self, style):
        match style:
            case 'snake':
                return '_'.join(self.elems)
            case 'upper_snake':
                return '_'.join(map(str.upper, self.elems))
            case 'camel':
                _iter = iter(self.elems)
                return next(_iter) + ''.join(map(str.capitalize, _iter))
            case 'pascal':
                return ''.join(map(str.capitalize, self.elems))
            case 'kebab':
                return '-'.join(self.elems)

def find(seq, predicate):
    for item in seq:
        if predicate(item):
            return item
    return None

def item_assign(value):
    return ast.Assign(
        lineno=1,
        targets=[ast.Name(id=Convertor(value[0], 'camel').export('upper_snake'))],
        value=ast.Constant(value=value[1]['id'])
    )

with open('res.json', encoding='utf-8') as json_file, open('res.py') as py_file:
    enums = json.load(json_file)
    module = ast.parse(py_file.read())
    if not module.body or not isinstance(module.body[0], ast.ImportFrom) or (module.body[0].module != 'enum' and not find(module.body[0].names, lambda a: a.name == 'IntEnum')):
        module.body.insert(0, ast.ImportFrom(
            module='enum',
            names=[ast.alias(name='IntEnum')]
        ))
    for enum in enums.items():
        pep_name = Convertor(enum[0], 'camel').export('pascal')
        existing_enum = find(module.body, lambda cd: isinstance(cd, ast.ClassDef) and cd.name == pep_name)
        if existing_enum:
            for value in enum[1].items():
                pep_field_name = Convertor(value[0], 'camel').export('upper_snake')
                existing_value = find(existing_enum.body, lambda ass: isinstance(ass, ast.Assign) and 
                    find(ass.targets, lambda name: name.id == pep_field_name))
                if existing_value:
                    existing_value.value = ast.Constant(value=value[1]['id'])
                else:
                    existing_enum.body.append(item_assign(value))
        else:
            existing_enum = ast.ClassDef(
                decorator_list=[],
                name=pep_name,
                bases=[ast.Name(id='IntEnum')],
                keywords=[],
                body=list(map(item_assign, enum[1].items()))
            )
            module.body.append(existing_enum)
        existing_enum.body.sort(key=lambda item: (isinstance(item, ast.Assign) and item.value.value) or float('inf'))

with open('res.py', 'w', encoding='utf-8') as output:
    output.write(ast.unparse(module))